/*
 * SerializeBasic.h
 *
 *  Created on: Dec 6, 2024
 *      Author: zhian
 */

#ifndef SERIALIZEBASIC_H_
#define SERIALIZEBASIC_H_
#include <nlohmann/json.hpp>
#include <Eigen/Dense>
#include <vector>
#include <ostream>
#include <map>
#include <fstream>
#include "JointData.h"

nlohmann::json serializeAffine3d(const Eigen::Affine3d& affine);
Eigen::Affine3d deserializeAffine3d(const nlohmann::json& j);

inline nlohmann::json serializeJointData(const JointData& jointData) {
    nlohmann::json j;
    j["data"] = jointData.data;
    j["ids"] = jointData.ids;
    j["m_byChain"] = jointData.isByChain();
    return j;
}
inline JointData deserializeJointData(const nlohmann::json& j) {
    JointData jointData;
    j.at("data").get_to(jointData.data);
    j.at("ids").get_to(jointData.ids);
    j.at("m_byChain").get_to(jointData.m_byChain);
    return jointData;
}

inline nlohmann::json serializeJointDataV(const std::vector<JointData>& jointDataV)
{
    nlohmann::json j = nlohmann::json::array();
    for ( const auto& jd : jointDataV)
		j.push_back(serializeJointData(jd));
    return j;
}

inline std::vector<JointData> deserializeJointDataV(const nlohmann::json& j)
{
	std::vector<JointData> jdv;
	for ( auto & item : j) {
		jdv.push_back(deserializeJointData(item));
	}
	return jdv;
}

inline nlohmann::json serializeMJointData(const MJointData& mj) {
    nlohmann::json j;
    j["data"] = serializeJointData(mj.data);
    j["pos"] = serializeAffine3d(mj.pos);
    j["moved"] = mj.moved;
    j["chainID"] = mj.chainID;
    return j;
}
inline MJointData deserializeMJointData(const nlohmann::json& j) {
    MJointData mjointData;
    mjointData.data = deserializeJointData(j["data"]);
    mjointData.pos = deserializeAffine3d(j["pos"]);
    j.at("moved").get_to(mjointData.moved);
    if(!mjointData.data.ids.empty()){
        mjointData.chainID = mjointData.data.ids.front();
    }else{

    }
    //j.at("chainID").get_to(mjointData.chainID);
    return mjointData;
}

inline nlohmann::json serializeMJointDataV(const std::vector<MJointData>& mjointDataV)
{
    nlohmann::json j = nlohmann::json::array();
    for ( const auto& jd : mjointDataV)
		j.push_back(serializeMJointData(jd));
    return j;
}

inline std::vector<MJointData> deserializeMJointDataV(const nlohmann::json& j)
{
	std::vector<MJointData> jdv;
	for ( auto & item : j) {
		jdv.push_back(deserializeMJointData(item));
	}
	return jdv;
}

inline nlohmann::json serializeMJointDataVV(const std::vector<std::vector<MJointData>>& mjointDataV)
{
    nlohmann::json j = nlohmann::json::array();
    for ( const auto& jd : mjointDataV)
		j.push_back(serializeMJointDataV(jd));
    return j;
}

inline std::vector<std::vector<MJointData>> deserializeMJointDataVV(const nlohmann::json& j)
{
	std::vector<std::vector<MJointData>> jdv;
	for ( auto & item : j) {
		jdv.push_back(deserializeMJointDataV(item));
	}
	return jdv;
}

inline std::map<int,std::vector<MJointData>> deserializeMJointDataMV(const nlohmann::json& j)
{
    std::map<int,std::vector<MJointData>> jdv;
    for (auto& [key, value] : j.items()) {
        int id = std::stoi(key);  // 将字符串转换回 int
        jdv[id].push_back(deserializeMJointData(value));
    }
    return jdv;
}

inline  nlohmann::json GetJsonByPath(const std::string &filePath)
{
    nlohmann::json j;
    if(filePath.empty()) return j;
    std::ifstream file(filePath);
    if (file.is_open()) {
        file >> j;
        file.close();
    }else{
        std::cerr << __FUNCTION__ << "\t Error Read :" << filePath << std::endl;
    }
    return j;
}


inline  void WriteJson(const std::string &filePath,const nlohmann::json &j)
{
    std::ofstream file(filePath);
    if (file.is_open()) {
        file << j.dump(4);
        file.close();
    } else {
        std::cerr <<__FUNCTION__ << " 无法保存到文件!  " <<filePath << std::endl;
    }
}




struct VideoModulData
{
    int ChainID;
    int WRL_ID;
    int partID;
    int steps;
    std::vector<MJointData> mj;
};


typedef VideoModulData OPH;
struct OnePartPath{
    OPH assm1;
    OPH dh1;
    OPH assm2;
    OPH dh2;

    OPH part1;
    OPH part2;
};


typedef std::vector<OPH> MHS;
typedef std::map<int,OnePartPath> DHM;

struct DMHStruct{
    int StationID=1;
    MHS mh;
    DHM dh;

    static std::vector<MJointData> MH2Vec(const MHS &mh);
    static std::vector<MJointData> OPH2Vec(const OPH &op);
};




inline nlohmann::json serializeVModul(const VideoModulData& vModul)
{
    nlohmann::json j;
    j["ChainID"] = vModul.ChainID;
    j["WRL_ID"] = vModul.WRL_ID;
    j["partID"] = vModul.partID;
    j["steps"] = vModul.steps;
    for ( const auto& mj : vModul.mj)
        j["mj"].push_back(serializeMJointData(mj));
    return j;
}


inline nlohmann::json serializeMHS(const MHS& mhs)
{
    nlohmann::json j ;
    for ( const auto& mhsi : mhs)
        j.push_back(serializeVModul(mhsi));
    return j;
}


inline nlohmann::json serializeDHS(const DHM& dhm)
{
    nlohmann::json j ;
    for(auto it=dhm.begin(); it!=dhm.end(); it++)
    {
        auto key = std::to_string(it->first);
        j[key]["assm1"] = serializeVModul(it->second.assm1);
        j[key]["dh1"] = serializeVModul(it->second.dh1);
        j[key]["assm2"] = serializeVModul(it->second.assm2);
        j[key]["dh2"] = serializeVModul(it->second.dh2);
        j[key]["part1"] = serializeVModul(it->second.part1);
        j[key]["part2"] = serializeVModul(it->second.part2);
    }
    return j;
}


inline nlohmann::json serializeDMH(const DMHStruct& dmh)
{
    nlohmann::json j ;
    j["StationID"] = dmh.StationID;
    j["mh"] = serializeMHS(dmh.mh);
    j["dh"] = serializeDHS(dmh.dh);
    return j;
}

inline VideoModulData deserializeVModul(const nlohmann::json& j) {
    VideoModulData vModul;
    vModul.ChainID = j.at("ChainID").get<int>();
    vModul.WRL_ID = j.at("WRL_ID").get<int>();
    vModul.partID = j.at("partID").get<int>();
    vModul.steps = j.at("steps").get<int>();

    auto &mj = j.at("mj");
    vModul.mj = deserializeMJointDataV(mj);
    return vModul;
}


inline MHS deserializeMHS(const nlohmann::json& j) {
    MHS mhs;
    for (const auto& item : j) {
        mhs.push_back(deserializeVModul(item));
    }
    return mhs;
}

inline std::map<int,OPH> deserializeMMHS(const nlohmann::json& j) {
    std::map<int,OPH> mhs;
//    for (const auto& item : j) {
//        mhs[item]=(deserializeVModul(item));
//    }

    for (auto& [key, value] : j.items()) {
        int id = std::stoi(key);
        mhs[id]=(deserializeVModul(value));
    }

    return mhs;
}


struct Uploader{
    MHS joint;
    MHS path;

    std::map<int,OPH> pathI;

    // 通过 json 库提供的 to_json 函数序列化
    friend void from_json(const nlohmann::json& j, Uploader& db) {
       db.joint = deserializeMHS(j.at("joint"));
       db.path = deserializeMHS(j.at("path"));
       db.pathI = deserializeMMHS(j.at("pathI"));
    }
};

//inline Uploader deserializeUploader(const nlohmann::json& j) {
//    MHS mhs;
//    for (const auto& item : j) {
//        mhs.push_back(deserializeVModul(item));
//    }
//    return mhs;
//}


inline DHM deserializeDHS(const nlohmann::json& j) {
    DHM dhm;
    for (auto it = j.begin(); it != j.end(); ++it) {
        int key = std::stoi(it.key()); // key == partID
        dhm[key].assm1 = deserializeVModul(it.value().at("assm1"));
        dhm[key].dh1 = deserializeVModul(it.value().at("dh1"));
        dhm[key].assm2 = deserializeVModul(it.value().at("assm2"));
        dhm[key].dh2 = deserializeVModul(it.value().at("dh2"));
        dhm[key].part1 = deserializeVModul(it.value().at("part1"));
        dhm[key].part2 = deserializeVModul(it.value().at("part2"));
    }
    return dhm;
}

inline DMHStruct deserializeDMH(const nlohmann::json& j) {
    DMHStruct dmh;
    dmh.StationID = j.at("StationID").get<int>();
    dmh.mh = deserializeMHS(j.at("mh"));
    dmh.dh = deserializeDHS(j.at("dh"));
    return dmh;
}
#endif /* SERIALIZEBASIC_H_ */
